import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class FileGet {
    public static void main(String[] args) {

        //失败次数
        int failTimes = 0;

        //视频存放路径
        String path = "/volume2/Relook/rest/video/";

        //下载视频类型
        String type = ".mp4";

        try {

            //Files工具类读取下载列表
            //files有两列，第一列为下载地址，第二列为保存文件名
            List<String> lines = Files.readAllLines(Path.of("./files.txt"));

            //循环下载
            for(String line : lines){
                //下载列表预处理，去除空行
                if (line.replace(" ","").equals("")){
                    continue;
                }

                String[] items = line.split(",");
                if(items.length!=2) continue;

                //组装保存文件名
                items[1] = path+items[1]+type;

                if(Files.exists(Paths.get(items[1]))) {
                    log("文件已存在，跳过下载   " + line);
                    continue;
                }

                if (!Files.exists(Paths.get(items[1]).getParent())) {
                    //递归创建所有路径
                    Files.createDirectories(Paths.get(items[1]).getParent());
                }
                //调用wget下载
                boolean result = wget(items[0].replace(" ",""), items[1]);
                //失败五次将等待2小时后重试
                if(result){
                    failTimes = 0;
                    log("成功 ==>> "+line);
                }else if(failTimes < 5) {
                    log("下载失败==>> "+line);
                    failTimes ++;
                }else {
                    log("下载失败==>> "+line);
                    log("======= 失败次数超过五次，将等待两小时后继续下载 =======");
                    TimeUnit.HOURS.sleep(2);
                    failTimes = 0;
                }
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

    }
    public static boolean wget(String url, String path){
        String command = null;

        //如果是m3u8文件用ffmpeg下载，否则用wget下载
        //ffmpeg是一个强大的视频处理工具
        if(url.endsWith("m3u8")){
            command = "/volume2/Relook/script/ffmpeg -i " + url + " -c copy " + path;
        }else {
            command = "wget -c -t 10 " + url.replace("https","http") + " -O " + path;
        }
        System.out.println(command);
        try {
            //构建执行命令的process
            Process process = Runtime.getRuntime().exec(command);

            //获取标准输入流，错误流
            BufferedReader reader1 = new BufferedReader(new InputStreamReader(process.getInputStream()));
            BufferedReader reader2 = new BufferedReader(new InputStreamReader(process.getErrorStream()));

            /**
             * 命令的执行都会涉及到标准输入流（命令的输出的地方），标准错误流（错误输出的地方）
             * 如果不处理这两个流的缓冲区，命令在执行过程中会无法输出而阻塞
             * 这里用多线程来专门处理这两个流
             */
            BufferThread thread1 = new BufferThread(reader1);
            thread1.setName("标准输出流线程");
            thread1.start();
            BufferThread thread2 = new BufferThread(reader2);
            thread2.setName("错误输出流线程");
            thread2.start();

            //阻塞直到等待到命令结束
            process.waitFor();
            //如果命令退出码为0则代表命令正常执行完毕
            if(process.exitValue()==0){
                return true;
            }
            return false;
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 包装一个log输出方法
     * @param msg
     * @throws IOException
     */
    public static void log(String msg) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        sb.append(" ");
        sb.append(msg);
        sb.append("\n");

        //输出日志到日志文件
        Files.write(Paths.get("./WgetLog1.txt"), sb.toString().getBytes(StandardCharsets.UTF_8),StandardOpenOption.APPEND,StandardOpenOption.CREATE);
        System.out.println(sb);
    }

    static class BufferThread extends Thread {
        BufferedReader reader;
        public BufferThread(BufferedReader reader){
            this.reader =reader;
        }
        @Override
        public void run() {
            while (true) {
                try {
                    //如果读到-1代表流读完了
                    //这里只是单纯地消耗流，不至于让缓冲区满阻塞命令执行
                    if (reader.read() == -1) break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
